/**
 * Copyright (c) 2011 Technical Centre Radio Systems Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ua.tcrs.tabula.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import ua.tcrs.tabula.Listener;
import ua.tcrs.tabula.Event;

public class MethodListener implements Listener<Object, Object> {
	private Object instance;
	private Method method;
	public MethodListener( Object instance, Method method ) {
		if ( method.getParameterTypes().length > 2 ) {
			throw new IllegalArgumentException( "Method "+method+" has too many arguments" );
		}
		if ( !Modifier.isStatic( method.getModifiers() ) && instance == null ) {
			throw new IllegalArgumentException( "Method "+method+" must be static" );
		}
		
		this.instance = instance;
		this.method = method;
		this.method.setAccessible(true);
	}
	public MethodListener( Method method ) {
		this( null, method );
	}
	public MethodListener( Class<?> clazz, String methodName ) throws NoSuchMethodException {
		this( null, clazz.getMethod( methodName, Event.class ) );
	}
	@Deprecated
	public MethodListener( String className, String methodName ) throws ClassNotFoundException, NoSuchMethodException {
		// Container always sets ContextClassLoader
		this( Thread.currentThread().getContextClassLoader().loadClass( className ), methodName );
	}
	public Object onEvent( Event<Object, Object> evt ) {
		try {
			// TODO: Create separate listeners for each variant
			switch ( method.getParameterTypes().length ) {
				case 0: return method.invoke( instance );
				case 1: return method.invoke( instance, evt );
				case 2: return method.invoke( instance, evt.getId(), evt.getBody() );
				default: return null; // Parameters count checked in constructor
			}
		} catch ( InvocationTargetException e ) {
			throw new RuntimeException( e.getCause() );
		} catch ( IllegalAccessException e ) {
			throw new RuntimeException( e );
		}
	}
}
